Option Explicit

'################################################################
' Discriptor
' 列定义
' 多列字符串计算列
'################################################################

Implements IDFFilterCol
Implements IDFFilterDoubleComputeCol

'################################################################
' Field
'################################################################

' 左计算参数: 原始列，可以是真实列 DFFilterSingleCol 或者其他包装类型
Private leftCol As IDFFilterCol
' 左计算参数: 原始列，可以是真实列 DFFilterSingleCol 或者其他包装类型
Private rightCol As IDFFilterCol

' --------------------------
' 初始化时需要获取的信息
' 当前列是不是字面量列
Private fieldIsLiteralCol As Boolean
' 当前列是不是聚合列
Private fieldIsAggregateCol As Boolean
' originCol 所使用的 Filter
' 如果使用了多个列，则设置为 Nothing
' 如果是字面量，也设置为 Nothing
Private parentDFFilter As DFFilter
' --------------------------

' 当前列的别名
' 需要手动设置
Private fieldAliasName As String

'################################################################
' Constructor
'################################################################
Private Sub Class_Initialize()
End Sub

Private Sub Class_Terminate()
End Sub

'################################################################
' Init
'################################################################
' @param left 左计算列
' @param right 右计算列
Public Sub Init(ByRef left As IDFFilterCol, ByRef right As IDFFilterCol)
    ' 1. 参数检测
    ' 1.1 left + right 必须不能为 Nothing
    If left Is Nothing Then
        Err.Raise 10001, Description:="parameter left must be not nothing"
        Exit Sub
    End If
    If right Is Nothing Then
        Err.Raise 10001, Description:="parameter right must be not nothing"
        Exit Sub
    End If

    ' 2. 保存基础参数
    Set leftCol = left
    Set rightCol = right

    ' 3. 计算引用信息
    ' 3.1 保存:当前列是不是字面量列
    '     只有左右两个计算列都是字面量时，当前列也是字面量
    fieldIsLiteralCol = (leftCol.isLiteralCol And rightCol.isLiteralCol)

    ' 3.2 检查当前列使用的 DFFilter
    If fieldIsLiteralCol Then
        ' 如果当前列已经是字面量列，则当前列不使用任何 parentDFFilter
        Set parentDFFilter = Nothing
    Else
        ' 3.2 检查左右两个列使用的 DFFilter
        If leftCol.isLiteralCol Then
            ' 如果左计算列是字面量列，则以右计算列为准
            Set parentDFFilter = rightCol.Filter
        ElseIf rightCol.isLiteralCol Then
            ' 如果右计算列是字面量列，则以左计算列为准
            Set parentDFFilter = leftCol.Filter
        Else
            ' 如果两个都不是字面量列，则:
            ' 同时获取左右两个列的 DFFilter 并合并，然后检查数量
            Dim leftFilterSet As ISet
            Dim rightFilterSet As ISet
            Set leftFilterSet = leftCol.getAllFilters
            Set rightFilterSet = rightCol.getAllFilters
            leftFilterSet.MergeSet rightFilterSet

            If leftFilterSet.Count = 1 Then
                Set parentDFFilter = leftFilterSet.Item(0)
            Else
                Set parentDFFilter = Nothing
            End If
    End If

    ' 3.3 检查是不是聚合列
    '     左右两列只要有一个是聚合列，当前列就是聚合列
    fieldIsAggregateCol = leftCol.isAggregateCol Or rightCol.isAggregateCol
End Sub

'################################################################
' Property
'################################################################
' 返回列名
' 如果当前列是多个列组合成的或是计算列，则返回 ""
Public Property Get IDFFilterCol_Name() As String
    ' 因为当前列是计算列，所以默认返回 ""
    IDFFilterCol_Name = ""
End Property

' 返回别名
' 如果当前列是多个列组合成的或是计算列（没有手动设置别名的），则返回 ""
Public Property Get IDFFilterCol_AliasName() As String
    IDFFilterCol_AliasName = fieldAliasName
End Property

' 返回别名
' 如果当前列是多个列组合成，则返回 Nothing
Public Property Get IDFFilterCol_Filter() As DFFilter
    Set IDFFilterCol_Filter = parentDFFilter
End Property

' 返回当前列的类型
Public Property Get IDFFilterCol_ColType() As DF_DataType
    ' 固定返回字符串类型
    IDFFilterCol_ColType = DF_DataType.DF_STRING
End Property

' 返回当前列的类型处理器
Public Property Get IDFFilterCol_ColTypeHandle() As IDFDataTypeHandler
    ' 固定返回字符串类型的处理器
    Set IDFFilterCol_ColTypeHandle = DFHelper.getDataTypeHandler(DF_DataType.DF_STRING)
End Property


'################################################################
' IDFFilterDoubleComputeCol Function
'################################################################
' 获取参与计算的左运算列对象
Public Function IDFFilterDoubleComputeCol_getLeftComputeCol() As IDFFilterCol
    Set IDFFilterDoubleComputeCol_getLeftComputeCol = leftCol
End Function

' 获取参与计算的右运算列对象
Public Function IDFFilterDoubleComputeCol_getRightComputeCol() As IDFFilterCol
    Set IDFFilterDoubleComputeCol_getRightComputeCol = rightCol
End Function

'################################################################
' IDFFilterCol Function
'################################################################

' ------------------------------------------------------
' 列操作
' ------------------------------------------------------
' 获取当前列中使用的所有真实列对象
' @return HashSet<DFFilterSingleCol>
Public Function IDFFilterCol_getRealUsedCol() As ISet
    ' 1. 如果当前列是字面量列，则返回一个空 Set
    ' 2. 如果左列是字面量列，则返回右列的使用的真实列 Set
    ' 3. 如果左列是字面量列，则返回右列的使用的真实列 Set
    ' 4. 同时获取左右两个列中的真实列 Set，然后合并
    If fieldIsLiteralCol Then
        Set IDFFilterCol_getRealUsedCol = UtilsSet.createHashSet
    ElseIf leftCol.isLiteralCol Then
        Set IDFFilterCol_getRealUsedCol = rightCol.getRealUsedCol
    ElseIf rightCol.isLiteralCol Then
        Set IDFFilterCol_getRealUsedCol = leftCol.getRealUsedCol
    Else
        Dim leftSet As ISet
        Dim rightSet As ISet
        Set leftSet = leftCol.getRealUsedCol
        Set rightSet = rightCol.getRealUsedCol
        leftSet.MergeSet rightSet

        Set IDFFilterCol_getRealUsedCol = leftSet
    End If
End Function

' 获取当前列中使用的所有 Filter
' @return HashSet<DFFilter>
Public Function IDFFilterCol_getAllFilters() As ISet
    ' 1. 如果当前列是字面量列，则返回一个空 Set
    ' 2. 如果 parentDFFilter 不是空，说明当前列只使用了一个 DFFilter，则创建一个 Set并返回
    ' 3. 如果 parentDFFilter 是 Nothing，说明当前列使用了多个 DFFilter
    '    则分别获取左右两列的 DFFilter 然后合并

    If fieldIsLiteralCol Then
        Set IDFFilterCol_getAllFilters = UtilsSet.createHashSet
    ElseIf Not parentDFFilter Is Nothing Then
        Set IDFFilterCol_getAllFilters = UtilsSet.createHashSet
        IDFFilterCol_getAllFilters.Add parentDFFilter
    Else
        Dim leftSet As ISet
        Dim rightSet As ISet
        Set leftSet = leftCol.getAllFilters
        Set rightSet = rightCol.getAllFilters
        leftSet.MergeSet rightSet

        Set IDFFilterCol_getAllFilters = leftSet
    End If
End Function

' 返回当前是否只是一个字面量列
Public Function IDFFilterCol_isLiteralCol() As Boolean
    ' 委托给 originCol，如果 originCol 是一个字面量列，
    ' 则当前计算列的结果仍然是字面量
    IDFFilterCol_isLiteralCol = fieldIsLiteralCol
End Function

' 返回当前是一个聚合计算列
' 这里有两种可能
'   1. 对于 IDFFilterAggCol 接口实现类，是聚合计算列
'   2. 对一个聚合计算列进行计算，计算结果仍然是聚合计算列
Public Function IDFFilterCol_isAggregateCol() As Boolean
    IDFFilterCol_isAggregateCol = fieldIsAggregateCol
End Function

' 返回当前是否只使用了一个 Filter 中的列
' 这里有三种可能
'   1. 只使用了一个 Filter 中的列   ---> True
'   2. 使用了多个 Filter 中的列     ---> False
'   3. 字面量列，没有使用任何 Filter 中的列 ---> False
Public Function IDFFilterCol_isUseSingleFilter() As Boolean
    IDFFilterCol_isUseSingleFilter = parentDFFilter Is Nothing
End Function

' 检查当前列使用的 DFFilter 是否和指定的 DFFilter 相同
' 如果是同表多列的组合，则默认返回 True
' 如果是多表多列的组合，则默认返回 False
Public Function IDFFilterCol_isSameFilter(ByRef filter As DFFilter) As Boolean
    ' 如果 originCol 中使用了多个 filter，则 parentDFFilter 是 Nothing，一定会返回 False
    ' 如果 originCol 中只使用了一个 filter，就返回其和方法参数的比较结果
    IDFFilterCol_isSameFilter = parentDFFilter Is filter
End Function

' 从 DFFilter 中获取当前活动行的数据
' 外部不应该主动调用
Public Function IDFFilterCol_unsafeGetActiveRowVal() As Variant
    IDFFilterCol_unsafeGetActiveRowVal = "" & leftSet.getActiveRowVal & rightSet.getActiveRowVal
End Function

' 克隆一个相同的对象
' 字面量计算列 + 真实列不需要克隆，因为这两种无法进行修改
Public Function IDFFilterCol_clone() As IDFFilterCol
    ' 1. 初始化
    Dim result As DFFilterDoubleColConcat
    Set result = New DFFilterDoubleColConcat
    result.Init leftCol.clone, rightCol.clone

    ' 2. 填充别名
    result.IDFFilterCol_alias fieldAliasName

    Set IDFFilterCol_clone = result
End Function
' ------------------------------------------------------
' Filter 过滤器语义操作
' ------------------------------------------------------
' ==================================
' 原地操作
' ==================================
' 返回自身
' 为当前 FilterCol 设置别名
' @param name 别名
' @return 返回当前 FilterCol 对象自身，以完成链式调用
Public Function IDFFilterCol_alias(ByRef name As String) As IDFFilterCol
    fieldAliasName = name
    Set IDFFilterCol_alias = Me
End Function


'///////////////////////////////////////////////////////////////////////////////////
' 通用生成/包装方法
'///////////////////////////////////////////////////////////////////////////////////
' ==================================
' 生成基础运算函数列
' ==================================
' 以当前 FilterCol 为基础创建一个加法计算列
'
' @param val 计算参数
'            可以是基础类型、IDFFilterCol类型(和另一个列进行计算)
' @return 加法计算列
Public Function IDFFilterCol_add(ByRef val As Variant) As IDFFilterCol
    Set IDFFilterCol_add = DFFilterHelper.unsafeCreateAddCol(Me, val)
End Function

' 以当前 FilterCol 为基础创建一个减法计算列
'
' @param val 计算参数
'            可以是基础类型（只对 INT、DECIMAL 类型有效，其他类型抛出异常）、
'            IDFFilterCol类型(和另一个列进行计算)
' @return 减法计算列
Public Function IDFFilterCol_subtract(ByRef val As Variant) As IDFFilterCol
    Set IDFFilterCol_subtract = DFFilterHelper.unsafeCreateSubtractCol(Me, val)
End Function

' 以当前 FilterCol 为基础创建一个乘法计算列
'
' @param val 计算参数
'            可以是基础类型（只对 INT、DECIMAL 类型有效，其他类型抛出异常）、
'            IDFFilterCol类型(和另一个列进行计算)
' @return 乘法计算列
Public Function IDFFilterCol_multiply(ByRef val As Variant) As IDFFilterCol
    Set IDFFilterCol_multiply = DFFilterHelper.unsafeCreateMultiplyCol(Me, val)
End Function

' 以当前 FilterCol 为基础创建一个除法计算列
'
' @param val 计算参数
'            可以是基础类型（只对 INT、DECIMAL 类型有效，其他类型抛出异常）、
'            IDFFilterCol类型(和另一个列进行计算)
' @return 除法计算列
Public Function IDFFilterCol_divide(ByRef val As Variant) As IDFFilterCol
    Set IDFFilterCol_divide = DFFilterHelper.unsafeCreateDivideCol(Me, val)
End Function

' 以当前 FilterCol 为基础创建一个字符串连接计算列
' @param val 计算参数
'            可以是基础类型（必须是字符串）、IDFFilterCol类型(和另一个列进行计算)
' @return 字符串连接计算列
Public Function IDFFilterCol_concat(ByRef val As Variant) As IDFFilterCol
    Set IDFFilterCol_concat = DFFilterHelper.unsafeCreateConcatCol(Me, val)
End Function

' ==================================
' 生成聚合函数列
' ==================================
' 在当前 FilterCol 的基础上生成最小值计算列
'
' @return IDFFilterCol + IDFFilterAggCol 最小值计算列
Public Function IDFFilterCol_min() As IDFFilterCol
    Set IDFFilterCol_min = DFFilterHelper.unsafeCreateMinCol(Me)
End Function

' 在当前 FilterCol 的基础上生成最大值计算列
'
' @return IDFFilterCol + IDFFilterAggCol 最大值计算列
Public Function IDFFilterCol_max() As IDFFilterCol
    Set IDFFilterCol_max = DFFilterHelper.unsafeCreateMaxCol(Me)
End Function

' 在当前 FilterCol 的基础上生成求和计算列
'
' @return IDFFilterCol + IDFFilterAggCol 求和计算列
Public Function IDFFilterCol_sum() As IDFFilterCol
    Set IDFFilterCol_sum = DFFilterHelper.unsafeCreateSumCol(Me)
End Function

' 在当前 FilterCol 的基础上生成求和计算列
'
' @return IDFFilterCol + IDFFilterAggCol 平均值计算列
Public Function IDFFilterCol_agg() As IDFFilterCol
    Set IDFFilterCol_agg = DFFilterHelper.unsafeCreateAggCol(Me)
End Function

' ==================================
' 条件生成器
' ==================================
' = 运算
'
' @param val 比较参数
'            可以是基础类型、IDFFilterCol 类型(和另一个列进行计算)
'            不能是 IDFFilterAggCol 聚合计算列，如果使用了将会抛出异常
Public Function IDFFilterCol_eq(ByRef val As Variant) As IDFFilterColCondition
    Set IDFFilterCol_eq = DFFilterHelper.unsafeCreateConditionEq(Me, val)
End Function

' != 运算
'
' @param val 比较参数
'            可以是基础类型、IDFFilterCol类型(和另一个列进行计算)
'            不能是 IDFFilterAggCol 聚合计算列，如果使用了将会抛出异常
Public Function IDFFilterCol_ne(ByRef val As Variant) As IDFFilterColCondition
    Set IDFFilterCol_ne = DFFilterHelper.unsafeCreateConditionNe(Me, val)
End Function

' > 运算
'
' @param val 比较参数
'            可以是基础类型、IDFFilterCol类型(和另一个列进行计算)
'            不能是 IDFFilterAggCol 聚合计算列，如果使用了将会抛出异常
Public Function IDFFilterCol_gt(ByRef val As Variant) As IDFFilterColCondition
    Set IDFFilterCol_gt = DFFilterHelper.unsafeCreateConditionGt(Me, val)
End Function

' < 运算
'
' @param val 比较参数
'            可以是基础类型、IDFFilterCol类型(和另一个列进行计算)
'            不能是 IDFFilterAggCol 聚合计算列，如果使用了将会抛出异常
Public Function IDFFilterCol_lt(ByRef val As Variant) As IDFFilterColCondition
    Set IDFFilterCol_lt = DFFilterHelper.unsafeCreateConditionLt(Me, val)
End Function

' >= 运算
'
' @param val 比较参数
'            可以是基础类型、IDFFilterCol类型(和另一个列进行计算)
'            不能是 IDFFilterAggCol 聚合计算列，如果使用了将会抛出异常
Public Function IDFFilterCol_ge(ByRef val As Variant) As IDFFilterColCondition
    Set IDFFilterCol_ge = DFFilterHelper.unsafeCreateConditionGe(Me, val)
End Function

' <= 运算
'
' @param val 比较参数
'            可以是基础类型、IDFFilterCol类型(和另一个列进行计算)
'            不能是 IDFFilterAggCol 聚合计算列，如果使用了将会抛出异常
Public Function IDFFilterCol_le(ByRef val As Variant) As IDFFilterColCondition
    Set IDFFilterCol_le = DFFilterHelper.unsafeCreateConditionLe(Me, val)
End Function

' in() 运算
'
' @param vs 比较参数数组
'            可以是基础类型、IDFFilterCol类型(和另一个列进行计算)
'            不能是 IDFFilterAggCol 聚合计算列，如果使用了将会抛出异常
Public Function IDFFilterCol_inVals(ByRef vs As Variant) As IDFFilterColCondition
    Set IDFFilterCol_inVals = DFFilterHelper.unsafeCreateConditionInVals(Me, vs)
End Function

' between 运算
'
' @param left 左值
' @param right 右值
'            可以是基础类型、IDFFilterCol类型(和另一个列进行计算)
'            不能是 IDFFilterAggCol 聚合计算列，如果使用了将会抛出异常
Public Function IDFFilterCol_between(ByRef left As Variant, ByRef right As Variant) As IDFFilterColCondition
    Set IDFFilterCol_between = DFFilterHelper.unsafeCreateConditionBetween(Me, left, right)
End Function
